package com.yfq.springframework.context.event;

import com.yfq.springframework.beans.BeanClassLoaderAware;
import com.yfq.springframework.beans.BeanFactoryAware;
import com.yfq.springframework.beans.BeansException;
import com.yfq.springframework.beans.factory.BeanFactory;
import com.yfq.springframework.context.ApplicationEvent;
import com.yfq.springframework.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @author: yfq
 * @date: 2023/1/31 17:52
 * @description:
 */
public abstract class AbstractApplicationEventMulticaster
        implements ApplicationEventMulticaster, BeanFactoryAware, BeanClassLoaderAware {
    final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    protected BeanFactory beanFactory;

    protected ClassLoader classLoader;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    /**
     * 获取事件的所有监听者
     */
    public Collection<ApplicationListener<?>> getApplicationListener(ApplicationEvent event) {
        Set<ApplicationListener<?>> listeners = new HashSet<>();

        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            if (supportsEvent(listener, event)) {
                listeners.add(listener);
            }
        }

        return listeners;
    }

    /**
     * 判断监听者是否对该事件感兴趣
     */
    @SuppressWarnings("all")
    private boolean supportsEvent(ApplicationListener<ApplicationEvent> listener, ApplicationEvent event) {
        Class<? extends ApplicationListener> listenerClass = listener.getClass();

        // 按照 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型，需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + className);
        }
        // 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同，或是否是其超类或超接口。
        // 判断eventClassName是否为event的父类或父接口
        return eventClassName.isAssignableFrom(event.getClass());
    }

}
